const RENDER_TO_DOM = Symbol('render to dom')

export class Component {
    constructor() {
        this.props = Object.create(null);
        this.children = [];
        this._root = null;
        this._range = null;
    }
    setAttribute(name, value) {
        this.props[name] = value
    }
    appendChild(component) {
        this.children.push(component)

    } 
    get vdom() {
        return this.render().vdom;
    }
    // get vchildren() {
    //     return this.children.map(child => child.vdom)
    // }
    [RENDER_TO_DOM](range) {
        this._range = range
        this._vdom = this.vdom
        // this.render()[RENDER_TO_DOM](range)
        this._vdom[RENDER_TO_DOM](range)
    }
    update () {
        let isSame = (oldNode, newNode) => {
            if (oldNode.type != newNode.type) {
                return false
            }
            for (let name in newNode.props) {
                if (newNode.props[name] != oldNode.props[name]) {
                    return false
                }
            }
            if (Object.keys(oldNode.props).length > Object.keys(newNode.props).length) {
                return false
            }
            if (newNode.type == '#text') {
                if (newNode.content != oldNode.content) {
                    return false
                }
            }
            return true
        }
        let update = (oldNode, newNode) => {
            // 根结点type和props完全一致， #text需要对比content
            if (!isSame(oldNode, newNode)) {
                newNode[RENDER_TO_DOM](oldNode._range)
                return
            }
            newNode._range = oldNode._range
            let newChildren = newNode.vchildren
            let oldChildren = oldNode.vchildren
            if (!newChildren || !newChildren.length) {
                return
            }
            let tailRange = oldChildren[oldChildren.length - 1]._range
            for (let i = 0; i < newChildren.length; i++) {
                let newChild = newChildren[i]
                let oldChild = oldChildren[i]
                if (i < oldChildren.length) {
                    update(oldChild, newChild)
                } else {
                    let range = document.createRange()
                    range.setStart(tailRange.endContainer, tailRange.endOffset)
                    range.setEnd(tailRange.endContainer, tailRange.endOffset)
                    newChild[RENDER_TO_DOM](range)
                    tailRange = range
                }
            }

        }
        let vdom = this.vdom
        update(this._vdom, vdom)
        this._vdom = vdom
    } 
    // rerender() {
    //     // this._range.deleteContents()
    //     // this[RENDER_TO_DOM](this._range)
    //     // 先插入再删除
    //     let oldRange = this._range;
    //     let range = document.createRange();
    //     range.setStart(oldRange.startContainer, oldRange.startOffset)
    //     range.setEnd(oldRange.startContainer, oldRange.startOffset)
    //     this[RENDER_TO_DOM](range)
    //     oldRange.setStart(range.endContainer, range.endOffset)
    //     oldRange.deleteContents()
    // }
    setState (newState) {
        // console.log(newState)
        // 没有state 或者 不是对象, 短路
        if (this.state == null || typeof this.state != "object") {
            this.setState = newState
            this.rerender()
            return;
        }
        // 深拷贝
        let merge = (oldState, newState) => {
            for (let p in newState) {
                if (oldState[p] == null || typeof oldState[p] != "object") {
                    oldState[p] = newState[p]
                } else {    
                    merge(oldState[p], newState[p])
                }
            }
        }
        merge(this.state, newState)
        // this.rerender()
        this.update()
    }
    // get root() {
    //     if (!this._root) {
    //         this._root = this.render().root
    //     }
    //     return this._root
    // }
}

class ElementWrapper extends Component {
    constructor(type) {
        super(type)
        this.type = type
        // this.root = document.createElement(type)
    }
    // setAttribute(name, value) {
    //     // 过滤事件， 如onClick
    //     if (name.match(/^on([\s\S]+)$/)) {
    //         // console.log(RegExp.$1)
    //         // 绑定事件， Click转click
    //         this.root.addEventListener(RegExp.$1.replace(/^[\s\S]/, c => c.toLowerCase()), value)
    //     } else if (name == 'className'){
    //         this.root.setAttribute('class', value)
    //     } else {
    //         this.root.setAttribute(name, value)
    //     }
    //     this.root.setAttribute(name, value)
    // }
    // appendChild(component) {
    //     // this.root.appendChild(component.root)
    //     let range = document.createRange()
    //     range.setStart(this.root, this.root.childNodes.length)
    //     range.setEnd(this.root, this.root.childNodes.length)
    //     component[RENDER_TO_DOM](range)
    // }
    get vdom() { 
        this.vchildren = this.children.map(child => child.vdom);
        return this
    }
    [RENDER_TO_DOM](range){
        // range.deleteContents()
        // range.insertNode(this.root)
        this._range = range
        // 实现setAttribute
        // range.deleteContents()
        let root = document.createElement(this.type)
        for (let name in this.props) {
            let value = this.props[name]
            if (name.match(/^on([\s\S]+)$/)) {
                // console.log(RegExp.$1)
                // 绑定事件， Click转click
                root.addEventListener(RegExp.$1.replace(/^[\s\S]/, c => c.toLowerCase()), value)
            } else {
                if (name == 'className') name = 'class'
                root.setAttribute(name, value)
            }
        }
        // 实现 appendChild
        if (!this.vchildren) this.vchildren = this.children.map(child => child.vdom)
        for (let child of this.vchildren) {
            let childRange = document.createRange()
            childRange.setStart(root, root.childNodes.length)
            childRange.setEnd(root, root.childNodes.length)
            child[RENDER_TO_DOM](childRange)
        }

        // range.insertNode(root)
        replaceContent(range, root)
    }
}

class TextWrapper extends Component{
    constructor(content) {
        super(content)
        this.type = '#text'
        this.content = content
        // this.root = document.createTextNode(content)
    }
    get vdom() {
        return this;
    }
    [RENDER_TO_DOM](range){
        this._range = range
    //     range.deleteContents()
    //   range.insertNode(this.root)
    let root = document.createTextNode(this.content)
    replaceContent(range, root)
    }
}

function replaceContent (range, node) {
    // 先插入后删除
    range.insertNode(node)
    range.setStartAfter(node)
    range.deleteContents()

    range.setStartBefore(node)
    range.setEndAfter(node)
}

export function createElement(tagName, attributes, ...rest) {
    let element
    if (typeof tagName == 'string') {
        element = new ElementWrapper(tagName)
    } else {
        element = new tagName
    }
    if (typeof attributes === 'object' && attributes instanceof Object) {
        for (const key in attributes) {
            element.setAttribute(key, attributes[key])
        }
    }
    let insertChildren = (children) => {
        // console.log(children)
        for(const child of children) {
            if (typeof child == 'string') {
                child = new TextWrapper(child) 
            }
            if (child === null) {
                continue;
            }
            if ((typeof child == 'object') && (child instanceof Array)) {
                insertChildren(child)
            } else {
                element.appendChild(child)
            }
        }
    }
    insertChildren(rest)
    return element
}

export function render(component, parentElement) {
    // parentElement.appendChild(component.root)
    let range = document.createRange()
    range.setStart(parentElement, 0)
    range.setEnd(parentElement, parentElement.childNodes.length)
    component[RENDER_TO_DOM](range)
}
